package org.jeecg.modules.demo.Kingdee.ApPay;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.jeecg.dingtalk.api.core.response.Response;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import io.lettuce.core.ScriptOutputType;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.constant.enums.MessageTypeEnum;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.demo.DPT.entity.Ticket;
import org.jeecg.modules.demo.DPT.service.ITicketService;
import org.jeecg.modules.system.entity.SysThirdAppConfig;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysThirdAppConfigService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl;
import org.jeecgframework.poi.excel.ExcelExportUtil;
import org.jeecgframework.poi.excel.entity.TemplateExportParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import static org.jeecg.modules.demo.util.KingdeeUtil.convertExcelToMapList;

/**
 * @Description:
 * @Author: jeecg-boot
 * @Date: 2025-05-14
 * @Version: V1.0
 */
@Tag(name = "")
@RestController
@RequestMapping("/KingDee")
@Slf4j
public class ApPayController extends JeecgController<Ticket, ITicketService> {

    @Value(value = "${kingdee.remoteHost}")
    private String remoteHost;
    @Value(value = "${kingdee.remoteUserName}")
    private String remoteUserName;
    @Value(value = "${kingdee.remotePassword}")
    private String remotePassword;

    /**
     * 导出对账单模板（金蝶应付单调用）
     *
     * @param parm
     * @return
     */
    @PostMapping(value = "/exporPayExcel")
    public Result<?> exporPayExcel(@RequestBody String parm) throws Exception {
        K3CloudApi api = new K3CloudApi();
        String json2 = "{\n" +
                "    \"FormId\": \"AP_Payable\",\n" +
                "    \"FieldKeys\": \"FID,FBILLNO,FSUPPLIERID.FName,FPURCHASEORGID.FName,FORDERNUMBER,FMaterialName,FMATERIALID.FNUMBER,FBASICUNITID.FName,FPriceQty,FTaxPrice,FALLAMOUNTFOR_D,FNoTaxAmountFor_D,FTAXAMOUNTFOR_D\",\n" +
                "    \"FilterString\": \"FID NOT IN ("+parm+")\",\n" +
                "    \"Limit\": 100,\n" +
                "}";
        List<JSONObject> tableData = JSON.parseArray(api.billQuery(json2), JSONObject.class);
        // 2. 配置参数（与原C#的路径、工作表名完全对齐）
        String templatePath = "D:\\KDTemplate\\对账单模板.xlsx"; // 模板路径
        String tempDir = "D:\\TempfilePath"; // 临时目录（对应C#的TempFileDir）
        String fileNamePrefix = "对账单"; // 文件前缀
        String newFilePath = getTempFilePath(tempDir, fileNamePrefix); // 临时文件路径
        String sheetName = "9月核对"; // 工作表名称（与原C#一致）
        int templateRowIndex = 0; // 模板行索引（从0开始，对应原C#的templateRowIndex）

        // 3. 调用核心方法生成Excel
        generateExcelFromTemplate(templatePath, newFilePath, sheetName, templateRowIndex, tableData);
        System.out.println("Excel生成成功！路径：" + newFilePath);
        return Result.OK("开始处理，完成后将发送钉钉消息");
    }

    /**
     * 基于模板生成带多行数据的Excel（核心方法）
     * @param templatePath 模板文件路径（例：D:\\KDTemplate\\对账单模板.xlsx）
     * @param newFilePath 新文件保存路径（例：D:\\Temp\\对账单_20251107160000.xlsx）
     * @param sheetName 模板中目标工作表名称（例："9月核对"）
     * @param templateRowIndex 模板行索引（数据从该行下方插入，从0开始计数）
     * @param tableData 数据源（List<JSONObject>，每个JSONObject对应一行数据，key=列名）
     * @throws IOException 文件操作异常
     */
    public static void generateExcelFromTemplate(String templatePath, String newFilePath,
                                                 String sheetName, int templateRowIndex,
                                                 List<JSONObject> tableData) throws IOException {
        // 1. 验证模板文件是否存在（对齐C#的File.Exists校验）
        File templateFile = new File(templatePath);
        if (!templateFile.exists()) {
            throw new IOException("模板文件不存在：" + templatePath);
        }

        // 2. 转换数据源：List<JSONObject> → List<Map<String, Object>>（AUTOPOI需Map格式）
        List<Map<String, String>> dataMapList = convertJsonToListMap(tableData);

        // 3. 配置AUTOPOI模板参数（指定模板路径、工作表，禁用默认样式覆盖）
        TemplateExportParams templateParams = new TemplateExportParams(templatePath);
        templateParams.setSheetName(sheetName); // 指定操作的工作表
//        templateParams.setExcludeColumnFiledNames(null); // 保留所有列数据
//        templateParams.setStyle(null); // 完全继承模板样式（不添加AUTOPOI默认样式）

        // 4. 构造AUTOPOI数据源格式（多行数据用"list"标识，与模板占位符对应）
        Map<String, Object> exportData = new HashMap<>();
        exportData.put("maplist", dataMapList); // "list"为固定循环标识，需与模板占位符匹配

        // 5. 生成Workbook（自动循环填充数据，保留模板样式：字体、边框、列宽等）
        Workbook workbook = ExcelExportUtil.exportExcel(templateParams, exportData);

        // 6. 保存新文件（覆盖已存在文件，对齐C#的FileStream.Create逻辑）
        try (FileOutputStream outputStream = new FileOutputStream(newFilePath)) {
            workbook.write(outputStream);
        } finally {
            workbook.close(); // 关闭流，释放POI资源（避免内存泄漏）
        }
    }

    /**
     * 辅助方法：将 List<JSONObject> 转换为 AUTOPOI 支持的 List<Map<String, Object>>
     * @param jsonList 原始JSON数据源
     * @return 转换后的Map列表
     */
    private static List<Map<String, String>> convertJsonToListMap(List<JSONObject> jsonList) {
        List<Map<String, String>> mapList = new ArrayList<>(jsonList.size());
        int index=1;
        for (JSONObject json : jsonList) {
            Map<String, String> dataMap = new LinkedHashMap<>(json.size());
            // 遍历JSONObject的所有key，转换为Map的键值对（保留数据类型：数字、字符串等）
            for (String key : json.keySet()) {
                Object value = json.get(key);
                // 对齐C#的Math.Round逻辑：若为数字，保留对应小数位（可选，根据需求调整）
                if (value instanceof Number) {
                    dataMap.put(key, formatNumberValue((Number) value, key).toString());
                } else {
                    dataMap.put(key, value == null ? "" : value.toString()); // 空值处理为空白字符串
                }
                dataMap.put("index",String.valueOf(index++));
            }
            mapList.add(dataMap);
        }
        return mapList;
    }

    /**
     * 辅助方法：对齐C#的Math.Round逻辑，按列名格式化数字（例：数量取整，金额保留2位小数）
     * @param number 原始数字值
     * @param columnName 列名（用于区分格式化规则）
     * @return 格式化后的数字
     */
    private static Object formatNumberValue(Number number, String columnName) {
        // 按列名定义格式化规则（完全对齐原C#代码的Math.Round逻辑）
        switch (columnName.toLowerCase()) {
            case "数量": // 原C#：FPriceQty 保留0位小数
                return Math.round(number.doubleValue());
            case "含税单价(rmb)": // 原C#：FTaxPrice 保留2位小数
            case "含税金额rmb":   // 原C#：FALLAMOUNTFOR_D 保留2位小数
            case "不含税金额":     // 原C#：FNoTaxAmountFor_D 保留2位小数
            case "税额":           // 原C#：FTAXAMOUNTFOR_D 保留2位小数
                return String.format("%.2f", number.doubleValue()); // 保留2位小数
            default:
                return number; // 其他列保持原始数字格式
        }
    }

    /**
     * 辅助方法：生成临时文件路径（模仿C#的PathUtils.GetPhysicalPath）
     * @param tempDir 临时目录（例："D:\\TempfilePath"）
     * @param fileNamePrefix 文件前缀（例："对账单"）
     * @return 带时间戳的唯一临时文件路径（例：D:\\TempfilePath\\对账单_20251107160000.xlsx）
     */
    public static String getTempFilePath(String tempDir, String fileNamePrefix) {
        // 创建临时目录（不存在则自动创建，对齐C#的目录处理逻辑）
        File tempDirFile = new File(tempDir);
        if (!tempDirFile.exists()) {
            tempDirFile.mkdirs(); // 递归创建多级目录
        }
        // 生成带时间戳的文件名（避免重复）
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        return tempDir + File.separator + fileNamePrefix + "_" + timeStamp + ".xlsx";
    }

}
